/**
 * 测试文件追加器
 * 智能处理已存在的测试文件，避免覆盖用户代码
 */

import * as fs from 'fs';
import * as path from 'path';
import { Logger } from '../../../src/logger/Logger';

export class TestFileAppender {
    /**
     * 智能写入测试文件
     * - 如果文件不存在：直接创建
     * - 如果文件存在：追加新的测试用例到测试类中（不覆盖）
     * - Git管理的文件不需要备份
     */
    public static async writeTestFile(
        testFilePath: string,
        newTestCode: string,
        options: {
            forceOverwrite?: boolean;
            createBackup?: boolean;  // 默认false，git已管理版本
        } = {}
    ): Promise<{
        success: boolean;
        action: 'created' | 'appended' | 'overwritten' | 'cancelled';
        message: string;
    }> {
        // 确保目录存在
        const testDir = path.dirname(testFilePath);
        if (!fs.existsSync(testDir)) {
            fs.mkdirSync(testDir, { recursive: true });
            Logger.info(`[TestFileAppender] 创建目录: ${testDir}`);
        }
        
        // 如果文件不存在，直接创建
        if (!fs.existsSync(testFilePath)) {
            fs.writeFileSync(testFilePath, newTestCode, 'utf8');
            Logger.info(`[TestFileAppender] ✅ 创建新文件: ${testFilePath}`);
            return {
                success: true,
                action: 'created',
                message: `测试文件已创建`
            };
        }
        
        // 文件已存在 - 默认追加模式（不覆盖）
        if (options.forceOverwrite) {
            // ⚠️ 强制覆盖模式（不推荐，仅在明确需要时使用）
            Logger.warn(`[TestFileAppender] ⚠️ 强制覆盖模式：${testFilePath}`);
            fs.writeFileSync(testFilePath, newTestCode, 'utf8');
            return {
                success: true,
                action: 'overwritten',
                message: `测试文件已覆盖（请使用git恢复如有误）`
            };
        }
        
        // ✅ 智能追加模式（默认且推荐）
        try {
            const existingContent = fs.readFileSync(testFilePath, 'utf8');
            
            // 统计信息
            const originalLines = existingContent.split('\n').length;
            
            const appendedContent = this.appendTestCases(existingContent, newTestCode);
            
            if (appendedContent === existingContent) {
                // 提取新测试用例名称，用于更详细的消息
                const newTestCases = this.extractTestCases(newTestCode);
                const testNames = newTestCases.map(tc => this.extractTestName(tc)).filter(n => n);
                
                let detailMessage = '⚠️ 未做任何修改，可能原因：\n';
                if (testNames.length === 0) {
                    detailMessage += '  • 新生成的代码中没有检测到有效的 HWTEST_F 测试用例\n';
                    detailMessage += '  • 建议：检查生成的代码格式是否正确\n';
                    Logger.warn(`[TestFileAppender] ❌ 新代码中未提取到测试用例`);
                } else {
                    detailMessage += `  • 以下测试用例已存在于文件中：\n`;
                    testNames.forEach(name => {
                        detailMessage += `    - ${name}\n`;
                    });
                    detailMessage += '  • 建议：使用 `git diff` 查看文件当前状态\n';
                    Logger.warn(`[TestFileAppender] ⚠️ 所有测试用例已存在: ${testNames.join(', ')}`);
                }
                
                return {
                    success: false,
                    action: 'cancelled',
                    message: detailMessage
                };
            }
            
            // 直接写入（git会管理版本，不需要备份）
            const newLines = appendedContent.split('\n').length;
            const addedLines = newLines - originalLines;
            
            fs.writeFileSync(testFilePath, appendedContent, 'utf8');
            Logger.info(`[TestFileAppender] ✅ 追加测试用例到: ${testFilePath} (+${addedLines} 行)`);
            
            return {
                success: true,
                action: 'appended',
                message: `✅ 已成功追加测试用例到现有文件\n\n` +
                        `📝 新增了 ${addedLines} 行代码\n` +
                        `💡 使用 \`git diff\` 查看具体更改`
            };
        } catch (error: any) {
            Logger.error(`[TestFileAppender] ❌ 追加失败: ${error.message}`);
            Logger.error(`[TestFileAppender] Stack: ${error.stack}`);
            return {
                success: false,
                action: 'cancelled',
                message: `❌ 追加失败: ${error.message}\n\n` +
                        `请检查文件权限和格式是否正确`
            };
        }
    }
    
    /**
     * 追加测试用例到现有文件
     * 策略：
     * 1. 提取新代码中的测试用例（HWTEST_F）
     * 2. 找到现有文件中测试类的结束位置（namespace末尾）
     * 3. 在结束位置之前插入新的测试用例
     */
    private static appendTestCases(existingContent: string, newTestCode: string): string {
        // 提取新代码中的测试用例
        const newTestCases = this.extractTestCases(newTestCode);
        
        if (newTestCases.length === 0) {
            Logger.warn(`[TestFileAppender] 新代码中未找到测试用例`);
            return existingContent;
        }
        
        Logger.info(`[TestFileAppender] 提取了 ${newTestCases.length} 个新测试用例`);
        
        // 检查是否有重复的测试用例名
        const duplicateTests: string[] = [];
        const filteredTestCases = newTestCases.filter(testCase => {
            const testName = this.extractTestName(testCase);
            if (existingContent.includes(testName)) {
                Logger.warn(`[TestFileAppender] 跳过重复的测试用例: ${testName}`);
                duplicateTests.push(testName);
                return false;
            }
            return true;
        });
        
        if (filteredTestCases.length === 0) {
            const dupList = duplicateTests.length > 0 
                ? `\n已存在的测试: ${duplicateTests.join(', ')}` 
                : '';
            Logger.warn(`[TestFileAppender] 所有测试用例已存在${dupList}`);
            return existingContent;  // 返回原内容，触发"未修改"消息
        }
        
        Logger.info(`[TestFileAppender] ✅ 将追加 ${filteredTestCases.length} 个新测试用例`);
        if (duplicateTests.length > 0) {
            Logger.info(`[TestFileAppender] ℹ️ 跳过 ${duplicateTests.length} 个已存在的测试: ${duplicateTests.join(', ')}`);
        }
        
        // 找到namespace的结束位置（在最后一个 } 之前）
        const lines = existingContent.split('\n');
        let insertPosition = -1;
        let braceCount = 0;
        
        // 从后往前找，找到namespace的结束大括号
        for (let i = lines.length - 1; i >= 0; i--) {
            const line = lines[i].trim();
            
            if (line === '}' || line.startsWith('}')) {
                braceCount++;
                
                // 通常namespace会有两个闭合大括号（namespace AAFwk 和 namespace OHOS）
                if (braceCount === 2) {
                    insertPosition = i;
                    break;
                }
            }
        }
        
        if (insertPosition === -1) {
            // 未找到合适的位置，追加到文件末尾
            Logger.warn(`[TestFileAppender] 未找到namespace结束位置，追加到文件末尾`);
            return existingContent + '\n\n' + filteredTestCases.join('\n\n') + '\n';
        }
        
        // 在找到的位置之前插入新的测试用例
        lines.splice(insertPosition, 0, '', ...filteredTestCases.map(tc => tc + '\n'));
        
        return lines.join('\n');
    }
    
    /**
     * 从代码中提取所有HWTEST_F测试用例
     */
    private static extractTestCases(code: string): string[] {
        const testCases: string[] = [];
        
        // 🔍 调试：记录生成的代码前200个字符
        Logger.info(`[TestFileAppender] 🔍 开始提取测试用例，代码长度: ${code.length}`);
        Logger.info(`[TestFileAppender] 🔍 代码前200字符: ${code.substring(0, 200).replace(/\n/g, '\\n')}`);
        
        // 🔍 检查是否包含 HWTEST_F 关键字
        const hasHwtestF = code.includes('HWTEST_F');
        Logger.info(`[TestFileAppender] 🔍 代码中${hasHwtestF ? '包含' : '不包含'} HWTEST_F 关键字`);
        
        if (!hasHwtestF) {
            Logger.warn(`[TestFileAppender] ⚠️ 代码中没有 HWTEST_F，可能模型只生成了 Mock 定义或其他代码`);
            return testCases;  // 提前返回空数组
        }
        
        // 匹配策略：
        // 1. 可选的注释块 (/** ... */)
        // 2. HWTEST_F 宏调用
        // 3. 函数体（匹配大括号平衡）
        
        // 方法1：先尝试匹配带注释的（标准格式）
        const regexWithComment = /\/\*\*[\s\S]*?\*\/\s*HWTEST_F\s*\([^)]+\)\s*\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}/g;
        let match;
        const matchedPositions: Array<{start: number, end: number}> = [];
        
        while ((match = regexWithComment.exec(code)) !== null) {
            testCases.push(match[0]);
            matchedPositions.push({start: match.index, end: match.index + match[0].length});
            Logger.info(`[TestFileAppender] 提取带注释的测试用例: ${this.extractTestName(match[0])}`);
        }
        
        // 方法2：匹配不带注释的HWTEST_F（兼容格式）
        const regexWithoutComment = /HWTEST_F\s*\([^)]+\)\s*\{(?:[^{}]|\{(?:[^{}]|\{[^{}]*\})*\})*\}/g;
        
        while ((match = regexWithoutComment.exec(code)) !== null) {
            // 检查是否已经被方法1匹配过（避免重复）
            const isAlreadyMatched = matchedPositions.some(pos => 
                match!.index >= pos.start && match!.index < pos.end
            );
            
            if (!isAlreadyMatched) {
                testCases.push(match[0]);
                Logger.info(`[TestFileAppender] 提取不带注释的测试用例: ${this.extractTestName(match[0])}`);
            }
        }
        
        Logger.info(`[TestFileAppender] 📊 总共提取了 ${testCases.length} 个测试用例`);
        return testCases;
    }
    
    /**
     * 从测试用例代码中提取测试名称
     */
    private static extractTestName(testCase: string): string {
        const match = testCase.match(/HWTEST_F\s*\(\s*\w+\s*,\s*(\w+)\s*,/);
        return match ? match[1] : '';
    }
    
}

